#include	"OnlinePlayer.h"
#include	"Balancer.h"
#include	"../network/CenterService.h"

#include	<protocols/Center.pb.h>
#include	<Utils.h>

bool OnlinePlayer::Send(int pf, const google::protobuf::Message & msg, uint32_t serial /* = 0 */) {
	Sender * sender = GService.Find(_at);
	if (sender) return sender->Reply(pf, msg, serial);
	return false;
}

std::string OnlinePlayerManager::CreateSession(const std::string & account) {
	std::string session = CreateID();
	_sessions[account] = session;
	return session;
}

int OnlinePlayerManager::CheckSession(const std::string & account, const std::string & session) {
	auto it = _sessions.find(account);
	if (it == _sessions.end()) return Proto::S_ENotLogin;
	if (it->second.compare(session) != 0) return Proto::S_EBadParam;
	return Proto::S_Success;
}

void OnlinePlayerManager::ClearSession(const std::string & account) {
	auto it = _sessions.find(account);
	if (it != _sessions.end()) _sessions.erase(it);
}

OnlinePlayer * OnlinePlayerManager::Launch(uint64_t at, const Core::RoleData & role) {
	OnlinePlayer * p = _players.Alloc(at, role);
	_name2player[role.name()] = p;
	_id2player[role.pid()] = p;
	_account2player[role.account()] = p;
	Balancer::Instance().Inc(at);
	return p;
}

OnlinePlayer * OnlinePlayerManager::Find(const std::string & name) {
	auto it = _name2player.find(name);
	if (it == _name2player.end()) return nullptr;
	return it->second;
}

OnlinePlayer * OnlinePlayerManager::FindByAccount(const std::string & account) {
	auto it = _account2player.find(account);
	if (it == _account2player.end()) return nullptr;
	return it->second;
}

OnlinePlayer * OnlinePlayerManager::Find(uint64_t id) {
	auto it = _id2player.find(id);
	if (it == _id2player.end()) return nullptr;
	return it->second;
}

void OnlinePlayerManager::Rename(OnlinePlayer * player, const std::string & name) {
	_name2player.erase(player->_name);
	_name2player[name] = player;
	player->_name = name;
}

void OnlinePlayerManager::Logout(uint64_t id) {
	OnlinePlayer * player = Find(id);
	if (!player) {
		LOG_ERR("Logout player offline: pid[%llu]", id);
		return;
	}

	Balancer::Instance().Dec(player->_at);
	_name2player.erase(player->_name);
	_id2player.erase(player->_id);
	_sessions.erase(player->_account);
	_players.Free(player);
}

void OnlinePlayerManager::Kickout(OnlinePlayer * player, int reason) {
	if (!player) return;

	Proto::CmdKickout cmd;
	cmd.set_pid(player->Id());
	cmd.set_reason((Proto::CmdKickout_Reason)reason);
	player->Send(Proto::CMD_KICKOUT, cmd);
}

void OnlinePlayerManager::Kickout(uint64_t id, int reason) {
	Kickout(Find(id), reason);
}

